#include "stdafx.h"
namespace libnt
{
	arg_parse::_impl::_impl()
	{
	}

	arg_parse::_impl::~_impl()
	{
	}
	void arg_parse::_impl::trim(string& out,const char* space)
	{
		out.erase(0,out.find_first_not_of(space));
		out.erase(out.find_last_not_of(space)+1);
	}

	bool arg_parse::_impl::_check_swit(argument& argu)
	{
		list<argument>::iterator iter;
		for (iter=m_args_in.begin();iter!=m_args_in.end();++iter)
		{
			if (iter->flag == argu.flag) 
			{
				argu.valp = iter->valp;
				return true;
			}
		}
		return false;
	}


	bool arg_parse::_impl::_parseopt(const char* option)
	{
		int len;
		char next_flag = 0;
		char curr_flag = 0;
		bool alnum  = false;
		argument arg;
		int i;
		//int opt_count;

		if ((option==NULL) || (option[0]==0))
			return false;
		
		if (!isoption(option))
			return false;
	
		len = strlen(option);
		
		i = 0;
		while (i<len)
		{
			curr_flag = option[i];
			next_flag = option[i+1];
			alnum = (curr_flag!=':');

			if (alnum) 
			{
				arg.flag = curr_flag;
				if (next_flag==':') 
				{
					arg.valp = (char*)1;
					i +=2;
				}
				else
				{
					arg.valp = NULL;
					i++;
				}
				m_args_in.push_back(arg);
				continue;
			}
			i++;
		}
		return (bool)m_args_in.size();

	}

	bool arg_parse::_impl::_checkopt()
	{
		return true;
	}

	bool arg_parse::_impl::_parse(int argc,char* argv[],const char* option)
	{
		int len;
		int pos;
		int i;
		arg_type type;
		char* curr = NULL;
		char* next = NULL;
		char  flag;
		argument arg;
		bool is_arg = false;

		if (argc==1)
			return false;

		if (!_parseopt(option)) 
			return false;

		m_args.empty();
		m_opts.empty();

		for (pos=1;pos<argc;++pos)
		{
			curr = argv[pos];
			len  = strlen(curr);
			type = get_type(curr);

			if (type==_opt_swit) 
			{
				for (i=1;i<len;++i)
				{
					next = argv[pos+1];
					is_arg = (get_type(next)==_opt_argu);

					arg.flag = curr[i];
					arg.valp = NULL;
					if (!_check_swit(arg)) 
						return false;
					if (arg.valp!=NULL && !is_arg) 
						return false;
					if (arg.valp!=NULL) {
						arg.valp = next;
						++pos;
					}
					m_opts.push_back(arg);
				}
			}
			else 
			{
				arg.flag = 0;
				arg.valp = curr;
				m_args.push_back(arg);
			}
		}
		m_arg = m_args.begin();
		m_opt = m_opts.begin();

		

		return true;
	}

	argument* arg_parse::_impl::_getopt()
	{
		argument* parg = NULL;
		if (m_opt==m_opts.end()) {
			m_opt = m_opts.begin();
			return NULL;
		}
		parg = &(*m_opt);
		++m_opt;
		return parg;
	}

	argument* arg_parse::_impl::_getarg()
	{
		argument* parg = NULL;
		if (m_arg==m_args.end()) {
			m_arg = m_args.begin();
			return NULL;
		}
		parg = &(*m_arg);
		++m_arg;
		return parg;
	}

	bool arg_parse::_impl::isalnums(const char* str)
	{
		int len = strlen(str);
		for (int i=0;i<len;++i)
		{
			if (!isalnum(str[i]))
				return false;
		}
		return true;
	}

	bool arg_parse::_impl::isoption(const char* str)
	{
		int len = str && strlen(str);
		for (int i=0;i<len;++i)
		{
			if (!(isalnum(str[i]) || str[i]==':'))
				return false;
		}
		return true;
	}
	


	arg_type arg_parse::_impl::get_type(char* str)
	{
		if (str==NULL) 
			return _opt_none;
		if (str[0]=='-' && str[1] && isalnums(&str[1])) 
		{
			return _opt_swit;
		}
		return _opt_argu;
	}



	arg_parse::arg_parse():m_impl(new _impl)
	{
	}

	void arg_parse::trim(string& out,const char* space)
	{
		m_impl->trim(out,space);
	}

	bool arg_parse::parse(int argc,char* argv[],const char* option)
	{
		return m_impl->_parse(argc,argv,option);
	}

	argument* arg_parse::getopt()
	{
		return m_impl->_getopt();
	}

	argument* arg_parse::getarg()
	{
		return m_impl->_getarg();
	}

	arg_parse::~arg_parse()
	{
		if (m_impl!=NULL)
			delete m_impl;
	}
}
